package cms.utils.newimgmerge.dto;

import org.apache.commons.collections.CollectionUtils;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.*;
import java.util.List;

/**
 *  用于img合并工具类传参
 *
 * @author dhf
 * 2022年08月19日 20:19:02
 */
public class ImageParamsDTO {
    /** 底板宽度  默认 1540px */
    private int containerWidth;

    /** 底板高度  由具体图片来计算，不用传参 */
    private int containerHeight;

    /** 横向图片间间隔  默认2px */
    private int horizontalInterval;

    /** 纵向图片间隔  默认 2px */
    private int verticalInterval;

    /** 横版图片  默认每行2张 */
    private int horizontalImgLineCount;

    /** 纵版图片   默认每行3张 */
    private int verticalImgLineCount;

    /** 横版图片标准宽度  （最好凑整） */
    private int horizontalImgStandardWidth;

    /** 纵版图片标准宽度  （最好凑整） */
    private int verticalImgStandardWidth;

    /** container的背景色 */
    private Color bgColor;

    private List<BufferedImage> originalImageList;

    private List<ImgDetailInfoDTO> horizontalImgList;

    private List<ImgDetailInfoDTO> verticalImgList;

    /** 所有行的信息 */
    private List<LineImageDTO> allLineInfoList;

    /** 宽高比的 comparator*/
    private static final Comparator<ImgDetailInfoDTO> WIDTH_HEIGHT_RATION_COMPARATOR = new Comparator<ImgDetailInfoDTO>() {
        @Override
        public int compare(ImgDetailInfoDTO o1, ImgDetailInfoDTO o2) {
            double v = o2.getWidthHeightRatio() - o1.getWidthHeightRatio();
            if(v == 0) {
                return 0;
            }
            return v > 0 ? 1 : -1;
        }
    };

    /** 目标文件保存位置 */
    private File targetFile;

    public ImageParamsDTO(int containerWidth, int horizontalInterval, int verticalInterval, int horizontalImgLineCount, int verticalImgLineCount, List<BufferedImage> originalImageList, File targetFile, Color bgColor) {
        this.containerWidth = containerWidth;
        this.horizontalInterval = horizontalInterval;
        this.verticalInterval = verticalInterval;
        this.horizontalImgLineCount = horizontalImgLineCount;
        this.verticalImgLineCount = verticalImgLineCount;
        this.targetFile = targetFile;
        this.originalImageList = originalImageList;
        this.bgColor = bgColor;
        //格式化横版和纵版的图片宽度
        this.formatWidth();
        //将图片分为横版和纵版，分别存入 horizontalImgList 和 verticalImgList
        this.divideHorizontalAndVerticalImg();
        //将 horizontalImgList 和 verticalImgList，按宽高比，逆序排序
        this.orderedHorizontalAndVerticalImg();
        //填充行信息
        this.formatLineImgInfo();
        //填充container高度
        this.saveContainerHeight();
        //每一行都按height逆序排序
        for (LineImageDTO lineDto : this.allLineInfoList) {
            Collections.sort(lineDto.getLineImageList(), new Comparator<ImgDetailInfoDTO>() {
                @Override
                public int compare(ImgDetailInfoDTO o1, ImgDetailInfoDTO o2) {
                    return o2.getStandardHeight() - o1.getStandardHeight();
                }
            });
        }
    }

    /**
     *  填充container高度
     *
     * @author dhf
     * 2022年08月19日 22:11:37
     */
    private void saveContainerHeight() {
        int sumHeight = 0;
        for (LineImageDTO lineImageDTO : this.allLineInfoList) {
            Integer lineHeight = lineImageDTO.getLineHeight();
            sumHeight += lineHeight;
        }
        this.containerHeight = (this.allLineInfoList.size() + 1) * this.verticalInterval + sumHeight;
    }

    /**
     * 将 horizontalImgList 和 verticalImgList，按宽高比，逆序排序
     *
     * @author dhf
     * 2022年08月19日 21:00:39
     */
    private void orderedHorizontalAndVerticalImg() {
        if(CollectionUtils.isNotEmpty(this.horizontalImgList)) {
            Collections.sort(this.horizontalImgList, WIDTH_HEIGHT_RATION_COMPARATOR);
        }
        if(CollectionUtils.isNotEmpty(this.verticalImgList)) {
            Collections.sort(this.verticalImgList, WIDTH_HEIGHT_RATION_COMPARATOR);
        }
    }

    /**
     * 将图片分为横版和纵版，分别存入 horizontalImgList 和 verticalImgList
     *
     * @author dhf
     * 2022年08月19日 21:00:27
     */
    private void divideHorizontalAndVerticalImg() {
        if(CollectionUtils.isNotEmpty(this.originalImageList)) {
            this.horizontalImgList = new ArrayList<>();
            this.verticalImgList = new ArrayList<>();
            for (BufferedImage image : this.originalImageList) {
                double widthHeightRatio = image.getWidth() * 1D / image.getHeight();
                int standardWidth = this.verticalImgStandardWidth;
                if(widthHeightRatio > 1) {
                    standardWidth = this.horizontalImgStandardWidth;
                }
                // standardWidth / standardHeight = widthHeightRatio
                int standardHeight = (int)(standardWidth / widthHeightRatio);
                //1横  2纵
                int horizonOrVertical = widthHeightRatio > 1 ? 1 : 2;
                ImgDetailInfoDTO dto = new ImgDetailInfoDTO(image, standardWidth, standardHeight, widthHeightRatio, horizonOrVertical);
                if(horizonOrVertical == 1) {
                    this.horizontalImgList.add(dto);
                } else {
                    this.verticalImgList.add(dto);
                }
            }
        }
    }

    /**
     * 格式化横版和纵版的图片宽度
     *
     * @author dhf
     * 2022年08月19日 20:22:33
     */
    private void formatWidth() {
        this.horizontalImgStandardWidth = (containerWidth - (horizontalInterval * (horizontalImgLineCount + 1))) / horizontalImgLineCount;
        this.verticalImgStandardWidth = (containerWidth - (verticalInterval * (verticalImgLineCount + 1))) / verticalImgLineCount;
    }

    /**
     * 填充行信息以及container高度
     *
     * @author dhf
     * 2022年08月19日 21:17:19
     */
    private void formatLineImgInfo() {
        if(CollectionUtils.isEmpty(this.horizontalImgList) && CollectionUtils.isEmpty(this.verticalImgList)) {
            return;
        }
        this.allLineInfoList = new ArrayList<>();
        Random r = new Random();
        int wOrh = r.nextInt(2) + 1;
        if(CollectionUtils.isNotEmpty(this.horizontalImgList) && this.horizontalImgList.size() >= this.horizontalImgLineCount
                && CollectionUtils.isNotEmpty(this.verticalImgList) && this.verticalImgList.size() >= this.verticalImgLineCount) {
            while (this.horizontalImgList.size() >= this.horizontalImgLineCount
                    && this.verticalImgList.size() >= this.verticalImgLineCount) {
                //横纵都够整行，那就橫一行、纵一行，交替
                LineImageDTO lineDtoH = getLineInfo(this.horizontalImgList, this.horizontalImgLineCount);
                LineImageDTO lineDtoV = getLineInfo(this.verticalImgList, this.verticalImgLineCount);
                if(wOrh == 1) {
                    this.allLineInfoList.add(lineDtoH);
                    this.allLineInfoList.add(lineDtoV);
                } else {
                    this.allLineInfoList.add(lineDtoV);
                    this.allLineInfoList.add(lineDtoH);
                }
            }
        }
        while (CollectionUtils.isNotEmpty(this.horizontalImgList)
                && this.horizontalImgList.size() >= this.horizontalImgLineCount) {
            LineImageDTO lineDtoH = getLineInfo(this.horizontalImgList, this.horizontalImgLineCount);
            this.allLineInfoList.add(lineDtoH);
        }
        while (CollectionUtils.isNotEmpty(this.verticalImgList)
                && this.verticalImgList.size() >= this.verticalImgLineCount) {
            LineImageDTO lineDtoV = getLineInfo(this.verticalImgList, this.verticalImgLineCount);
            this.allLineInfoList.add(lineDtoV);
        }
        //到此为止，就都不够满行了，进行最后的组装
        //先横
        List<ImgDetailInfoDTO> imgListCurrLine01 = new ArrayList<>();
        int maxHeight01 = 0;
        for (int i = this.horizontalImgList.size() - 1; i >= 0; i--) {
            ImgDetailInfoDTO dto = this.horizontalImgList.get(i);
            imgListCurrLine01.add(dto);
            if(maxHeight01 < dto.getStandardHeight()) {
                maxHeight01 = dto.getStandardHeight();
            }
            this.horizontalImgList.remove(i);
        }
        for (int i = this.verticalImgList.size() - 1; i >= 0; i--) {
            //当前有效宽度
            int currValidWidth = (imgListCurrLine01.size() * this.horizontalImgStandardWidth)
                    + ((imgListCurrLine01.size() + 1) * horizontalInterval);
            //剩余可用宽度
            int remindWidth = this.containerWidth - currValidWidth;
            if(remindWidth >= this.verticalImgStandardWidth) {
                ImgDetailInfoDTO dto = this.verticalImgList.get(i);
                imgListCurrLine01.add(dto);
                if(maxHeight01 < dto.getStandardHeight()) {
                    maxHeight01 = dto.getStandardHeight();
                }
                this.verticalImgList.remove(i);
            } else {
                //换行
                this.allLineInfoList.add(new LineImageDTO(imgListCurrLine01, maxHeight01));
                //第二行
                this.allLineInfoList.add(getLineInfo(this.verticalImgList, this.verticalImgList.size()));
                return;
            }
        }
        //如果程序能走到这里，说明最后一行就组装好了
        this.allLineInfoList.add(new LineImageDTO(imgListCurrLine01, maxHeight01));
    }

    /**
     * 从list中获取一行
     *
     * @author dhf
     * 2022年08月19日 21:46:18
     */
    private LineImageDTO getLineInfo(List<ImgDetailInfoDTO> imgList, int count) {
        List<ImgDetailInfoDTO> lineImageList = new ArrayList<>();
        int maxHeight = 0;
        for (int i = count - 1; i >= 0; i--) {
            ImgDetailInfoDTO imgInfo = imgList.get(i);
            lineImageList.add(imgInfo);
            if(maxHeight < imgInfo.getStandardHeight()) {
                maxHeight = imgInfo.getStandardHeight();
            }
            imgList.remove(i);
        }
        LineImageDTO lineDto = new LineImageDTO(lineImageList, maxHeight);
        return lineDto;
    }


    public int getContainerWidth() {
        return containerWidth;
    }

    public void setContainerWidth(int containerWidth) {
        this.containerWidth = containerWidth;
    }

    public int getHorizontalInterval() {
        return horizontalInterval;
    }

    public void setHorizontalInterval(int horizontalInterval) {
        this.horizontalInterval = horizontalInterval;
    }

    public int getVerticalInterval() {
        return verticalInterval;
    }

    public void setVerticalInterval(int verticalInterval) {
        this.verticalInterval = verticalInterval;
    }

    public int getHorizontalImgLineCount() {
        return horizontalImgLineCount;
    }

    public void setHorizontalImgLineCount(int horizontalImgLineCount) {
        this.horizontalImgLineCount = horizontalImgLineCount;
    }

    public int getVerticalImgLineCount() {
        return verticalImgLineCount;
    }

    public void setVerticalImgLineCount(int verticalImgLineCount) {
        this.verticalImgLineCount = verticalImgLineCount;
    }

    public int getHorizontalImgStandardWidth() {
        return horizontalImgStandardWidth;
    }

    public void setHorizontalImgStandardWidth(int horizontalImgStandardWidth) {
        this.horizontalImgStandardWidth = horizontalImgStandardWidth;
    }

    public int getVerticalImgStandardWidth() {
        return verticalImgStandardWidth;
    }

    public void setVerticalImgStandardWidth(int verticalImgStandardWidth) {
        this.verticalImgStandardWidth = verticalImgStandardWidth;
    }

    public File getTargetFile() {
        return targetFile;
    }

    public void setTargetFile(File targetFile) {
        this.targetFile = targetFile;
    }

    public List<BufferedImage> getOriginalImageList() {
        return originalImageList;
    }

    public void setOriginalImageList(List<BufferedImage> originalImageList) {
        this.originalImageList = originalImageList;
    }

    public List<ImgDetailInfoDTO> getHorizontalImgList() {
        return horizontalImgList;
    }

    public void setHorizontalImgList(List<ImgDetailInfoDTO> horizontalImgList) {
        this.horizontalImgList = horizontalImgList;
    }

    public List<ImgDetailInfoDTO> getVerticalImgList() {
        return verticalImgList;
    }

    public void setVerticalImgList(List<ImgDetailInfoDTO> verticalImgList) {
        this.verticalImgList = verticalImgList;
    }

    public int getContainerHeight() {
        return containerHeight;
    }

    public void setContainerHeight(int containerHeight) {
        this.containerHeight = containerHeight;
    }

    public List<LineImageDTO> getAllLineInfoList() {
        return allLineInfoList;
    }

    public void setAllLineInfoList(List<LineImageDTO> allLineInfoList) {
        this.allLineInfoList = allLineInfoList;
    }

    public Color getBgColor() {
        return bgColor;
    }

    public void setBgColor(Color bgColor) {
        this.bgColor = bgColor;
    }
}
